﻿using System;
using System.Workflow.Activities;
using System.ComponentModel;
using TPG.SharePoint.Workflow.Activities.Design;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel;
using Microsoft.SharePoint.Workflow;
using System.Workflow.ComponentModel.Compiler;
using System.Drawing.Design;
using System.ComponentModel.Design;

namespace TPG.SharePoint.Workflow.Activities
{
    /// <summary>
    /// 
    /// </summary>
    [Designer(typeof(OnWorkflowActivatedDesigner), typeof(IDesigner)),
    ToolboxItem(typeof(ActivityToolboxItem))]
    internal class OnWorkflowActivated
        : HandleExternalEventActivity, IDynamicPropertyTypeProvider
    {
        internal const string AssociationDataProperty = "AssociationData";
        internal const string InstantiationDataProperty = "InstantiationData";

        public static DependencyProperty WorkflowIdProperty =
            DependencyProperty.Register("WorkflowId", typeof(Guid), 
            typeof(OnWorkflowActivated), new PropertyMetadata(Guid.Empty));

        public static DependencyProperty WorkflowPropertiesProperty =
            DependencyProperty.Register("WorkflowProperties", typeof(SPWorkflowActivationProperties),
            typeof(OnWorkflowActivated));

        [Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        ValidationOption(ValidationOption.Optional)]
        public Guid WorkflowId
        {
            get { return (Guid)GetValue(WorkflowIdProperty); }
            set { SetValue(WorkflowIdProperty, value); }
        }

        [ValidationOption(ValidationOption.Required)]
        public SPWorkflowActivationProperties WorkflowProperties
        {
            get { return (SPWorkflowActivationProperties)GetValue(WorkflowPropertiesProperty); }
            set { SetValue(WorkflowPropertiesProperty, value); }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Type InterfaceType
        {
            get { return typeof(ISharePointService); }
        }

        [Editor(typeof(TypeBrowserEditor), typeof(UITypeEditor)),
        RefreshProperties(RefreshProperties.All)]
        public Type AssociationDataType { get; set; }

        [Editor(typeof(TypeBrowserEditor), typeof(UITypeEditor)),
        RefreshProperties(RefreshProperties.All)]
        public Type InstantiationDataType { get; set; }

        public OnWorkflowActivated()
        {
            InterfaceType = typeof(ISharePointService);
            EventName = "OnWorkflowActivated";
        }

        protected override void OnInvoked(EventArgs e)
        {
            WorkflowId = ((SPActivationEventArgs)e).workflowId;
            SPWorkflowActivationProperties properties = ((SPActivationEventArgs)e).properties;
            WorkflowProperties = properties;
            if (AssociationDataType != null)
            {
                object associationData = Deserialize(properties.AssociationData,
                    properties.Workflow.ParentAssociation.BaseTemplate,
                    PageType.Association, AssociationDataType);
                SetVirtualProperty(OnWorkflowActivated.AssociationDataProperty, associationData);
            }
            if (InstantiationDataType != null)
            {
                object instantiationData = Deserialize(properties.InitiationData,
                    properties.Workflow.ParentAssociation.BaseTemplate,
                    PageType.Instantiation, InstantiationDataType);
                SetVirtualProperty(OnWorkflowActivated.InstantiationDataProperty, instantiationData);
            }
        }

        internal object GetVirtualProperty(string name)
        {
            object value = null;
            if (ParameterBindings != null && ParameterBindings.Contains(name))
            {
                WorkflowParameterBinding binding = ParameterBindings[name];
                if (binding.IsBindingSet(WorkflowParameterBinding.ValueProperty))
                {
                    value = binding.GetBinding(WorkflowParameterBinding.ValueProperty);
                }
                else
                {
                    value = binding.GetValue(WorkflowParameterBinding.ValueProperty);
                }
            }
            return value;
        }

        internal void SetVirtualProperty(string name, object value)
        {
            if (ParameterBindings != null)
            {
                WorkflowParameterBinding binding = null;
                if (ParameterBindings.Contains(name))
                {
                    binding = ParameterBindings[name];
                }
                else
                {
                    binding = new WorkflowParameterBinding(name);
                    ParameterBindings.Add(binding);
                }
                if (value is ActivityBind)
                {
                    binding.SetBinding(WorkflowParameterBinding.ValueProperty, (ActivityBind)value);
                }
                else
                {
                    binding.SetValue(WorkflowParameterBinding.ValueProperty, value);
                }
            }
        }

        object Deserialize(string data, SPWorkflowTemplate template, PageType pageType, Type dataType)
        {
            SerializationMode? mode = WorkflowConfiguration.GetSerializationMode(template, pageType);
            if (mode == SerializationMode.Binary)
            {
                return WorkflowDataSerializer.DeserializeFromBase64String(data);
            }
            else
            {
                return WorkflowDataSerializer.DeserializeFromXmlString(data, dataType);
            }
        }

        #region IDynamicPropertyTypeProvider Members

        AccessTypes IDynamicPropertyTypeProvider.GetAccessType(
            IServiceProvider serviceProvider, string propertyName)
        {
            return AccessTypes.Read;
        }

        Type IDynamicPropertyTypeProvider.GetPropertyType(
            IServiceProvider serviceProvider, string propertyName)
        {
            if (propertyName == AssociationDataProperty)
            {
                return AssociationDataType;
            }
            if (propertyName == InstantiationDataProperty)
            {
                return InstantiationDataType;
            }
            return null;
        }

        #endregion
    }
}
